<template>
  <div v-loading="!isReady" class="app-container">
    <operation-bar
      v-model:query-params="queryParams"
      :field="queryField"
      :permission-prefix="permissionPrefix"
      :single="single"
      :multiple="multiple"
      :handle-query="handleQuery"
      :handle-add="handleAdd"
      :handle-update="handleUpdate"
      :handle-selection-delete="handleDelete"
      :handle-download-tpl="handleDownloadTpl"
      :handle-upload="handleUpload"
      :handle-export="handleExport"
    />
    <table-list
      v-model:page-params="pageParams"
      :loading="loading"
      :list="list"
      :field="tableField"
      :total="total"
      :permission-prefix="permissionPrefix"
      :get-list="getList"
      :handle-selection-change="handleSelectionChange"
      :handle-delete="handleDelete"
      :handle-update="handleUpdate"
    />
    <add-update-dialog
      v-model="open"
      v-model:form="form"
      :title="title"
      :submit-form="submitForm"
      :cancel="cancel"
      :field="formField"
    />
    <upload-dialog
      ref="uploadRef"
      :import-data="handleImportData"
      :handle-download-tpl="handleDownloadTpl"
      @success="handleQuery"
    />
  </div>
</template>

<script setup name="Curd">
  import { ref } from 'vue';
  import { useRoute } from 'vue-router';
  import OperationBar from './components/operation-bar';
  import TableList from './components/table-list';
  import AddUpdateDialog from './components/add-update-dialog';
  import UploadDialog from './components/upload-dialog';
  import { getTable } from '@/api/web/bu/form';
  import { getDicts } from '@/api/system/dict/data';
  import { selectDictLabels } from '@/utils/base';
  import {
    listItem,
    getItem,
    addItem,
    updateItem,
    delItem,
    downloadTpl,
    exportData,
    importData,
  } from '@/api/web/bu/curd';
  import modal from '@/plugins/modal';

  const route = useRoute();
  const isReady = ref(false);
  const list = ref([]);
  const open = ref(false);
  const loading = ref(false);
  const ids = ref([]);
  const single = ref(true);
  const multiple = ref(true);
  const total = ref(0);
  const title = ref('');
  const uploadRef = ref(null);

  // 新增 修改 表单
  const form = ref({});
  // 分页参数
  const pageParams = ref({ pageNum: 1, pageSize: 10 });
  // 搜索项 和 搜索参数
  const queryField = ref([]);
  const queryParams = ref({});
  // 表单项 和 表单参数
  const formField = ref([]);
  const formParams = ref({});
  // 列表项
  const tableField = ref([]);

  const primaryKey = ref('ID');
  const permissionPrefix = ref('');
  const dicts = ref({});
  const multiOptControlType = ['select', 'radio', 'checkbox'];
  const reMap = new Map([
    ['邮件', /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/],
    ['手机号', /^[1][3,4,5,7,8][0-9]{9}$/],
    ['身份证号', /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/],
    ['港澳通行证', /^[HMhm]{1}([0-9]{10}|[0-9]{8})$/],
    ['字母', /^[0-9]+$/],
    ['数字', /^[a-zA-Z]+$/],
  ]);
  const formatMap = new Map([
    ['yyyy-MM-dd', 'YYYY-MM-DD'],
    ['yyyy/MM/dd', 'YYYY/MM/DD'],
    ['yyyy年MM月dd日', 'YYYY年MM月DD日'],
    ['HH:mm', 'HH:mm'],
    ['HH:mm:ss', 'HH:mm:ss'],
    ['yyyy-MM-dd HH:mm:ss', 'YYYY-MM-DD HH:mm:ss'],
    ['yyyy/MM/dd HH:mm:ss', 'YYYY/MM/DD HH:mm:ss'],
    ['yyyy年MM月dd日 HH时mm分ss秒', 'YYYY年MM月DD日 HH时mm分ss秒'],
  ]);

  const getList = ref(null);
  const cancel = ref(null);
  const reset = ref(null);
  const handleQuery = ref(null);
  const handleAdd = ref(null);
  const handleUpdate = ref(null);
  const submitForm = ref(null);
  const handleDelete = ref(null);
  const handleDownloadTpl = ref(null);
  const handleExport = ref(null);
  const handleImportData = ref(null);

  function handleSelectionChange(selection) {
    ids.value = selection.map((item) => item[primaryKey.value]);
    single.value = selection.length !== 1;
    multiple.value = !selection.length;
  }

  function handleUpload() {
    uploadRef.value?.handleImport();
  }

  async function useDict(...args) {
    const ans = {};
    for (const d of args) {
      ans[d] = (await getDicts(d)).data.map((p) => ({
        label: p.dictLabel,
        value: p.dictValue,
      }));
    }
    return ans;
  }

  function formatConstantDict(...args) {
    const ans = {};
    for (const d of args) {
      const k = `${d.colName}_TYPE`;
      const v = d.constantDictContent
        .split(',')
        .map((k) => k.split('='))
        .map((k) => ({
          label: k[0],
          value: k[1],
        }));
      ans[k] = v;
    }
    return ans;
  }

  async function scanDict(formCols) {
    const sysDictKey = formCols
      .filter((k) => k.relationDictType === '系统字典' && k.sysDictType)
      .map((k) => k.sysDictType);
    const sysDictOption = await useDict(...sysDictKey);

    const constantDictKey = formCols.filter(
      (k) => k.relationDictType === '常量字典' && k.constantDictContent,
    );
    const constantDictOption = formatConstantDict(...constantDictKey);

    dicts.value = {
      ...sysDictOption,
      ...constantDictOption,
    };
  }

  function genQueryField(formCols) {
    const queryConditionMap = new Map([
      ['gt', '大于'],
      ['gte', '大于等于'],
      ['lt', '小于'],
      ['lte', '小于等于'],
    ]);

    queryField.value = formCols
      .filter((k) => !k.primary && k.queryCondition !== 'not' && k.queryCondition)
      .map((k) => ({
        type:
          k.controlType === 'DatetimePicker'
            ? 'DatePicker'
            : k.controlType === 'password' || k.controlType === 'textarea'
              ? 'input'
              : k.controlType,
        title: k.fieldName,
        field: k.colName,
        props: {
          placeholder:
            k.fieldRemark || `请${k.controlType === 'select' ? '选择' : '输入'}${k.fieldName}`,
          clearable: true,
          filterable: true,
          multiple: k.queryCondition === 'in',
          valueFormat: formatMap.get(k.format) || k.format || '',
          type:
            k.controlType === 'DatetimePicker'
              ? `datetime${k.queryCondition === 'range' ? 'range' : ''}`
              : k.controlType === 'DatePicker'
                ? `date${k.queryCondition === 'range' ? 'range' : ''}`
                : null,
          isRange: k.controlType === 'TimePicker' && k.queryCondition === 'range',
        },
        children: [].concat(
          queryConditionMap.get(k.queryCondition)
            ? {
                type: 'span',
                slot: 'prefix',
                children: [queryConditionMap.get(k.queryCondition)],
              }
            : [],
        ),
        ext: k,
        ...(multiOptControlType.includes(k.controlType)
          ? {
              options:
                dicts.value[
                  k.relationDictType === '系统字典'
                    ? k.sysDictType
                    : k.relationDictType === '常量字典'
                      ? `${k.colName}_TYPE`
                      : Symbol()
                ] || [],
            }
          : {}),
        ...(k.relationDictType === '行政区划'
          ? {
              emit: ['focus'],
              emitPrefix: k.colName.replace('_', '').toLowerCase(),
            }
          : {}),
      }));

    queryParams.value = queryField.value.reduce((prev, curr) => {
      prev[curr.field] = curr.ext.controlType === 'checkbox' ? [] : null;
      return prev;
    }, {});
  }

  function genFormField(formCols) {
    formField.value = formCols.map((k) => ({
      type:
        k.controlType === 'DatetimePicker'
          ? 'DatePicker'
          : k.controlType === 'password' || k.controlType === 'textarea'
            ? 'input'
            : k.controlType,
      title: k.fieldName,
      field: k.colName,
      hidden: k.primary,
      props: {
        placeholder:
          k.fieldRemark || `请${k.controlType === 'select' ? '选择' : '输入'}${k.fieldName}`,
        clearable: true,
        filterable: true,
        multiple: k.queryCondition === 'in',
        valueFormat: formatMap.get(k.format) || k.format || '',
        'show-password': k.controlType === 'password',
        type:
          k.controlType === 'DatetimePicker'
            ? `datetime${k.queryCondition === 'range' ? '' : ''}`
            : k.controlType === 'DatePicker'
              ? `date${k.queryCondition === 'range' ? '' : ''}`
              : k.controlType === 'password'
                ? 'password'
                : k.controlType === 'textarea'
                  ? 'textarea'
                  : null,
        isRange: k.controlType === 'TimePicker' && k.queryCondition === 'range',
      },
      validate: [{ required: k.isRequired, message: `${k.fieldName}不能为空`, trigger: 'blur' }]
        .concat(
          k.validator
            ? {
                pattern: reMap.get(k.validator) || /.*/,
                message: `${k.validator}格式不正确`,
              }
            : [],
        )
        .concat(
          k.regexpStr
            ? {
                pattern: new RegExp((k.regexpStr || '').replace(/(^\/|\/$)/g, '')),
                message: '格式不正确',
              }
            : [],
        ),
      ext: k,
      ...(multiOptControlType.includes(k.controlType)
        ? {
            options:
              dicts.value[
                k.relationDictType === '系统字典'
                  ? k.sysDictType
                  : k.relationDictType === '常量字典'
                    ? `${k.colName}_TYPE`
                    : Symbol()
              ] || [],
          }
        : {}),
      ...(k.relationDictType === '行政区划'
        ? {
            emit: ['focus'],
            emitPrefix: k.colName.replace('_', '').toLowerCase(),
          }
        : {}),
    }));
    formParams.value = formField.value.reduce((prev, curr) => {
      prev[curr.field] = curr.ext.controlType === 'checkbox' ? [] : curr.ext.fieldDefault || null;
      return prev;
    }, {});
  }

  function genTableField(formCols) {
    tableField.value = formCols
      .filter((k) => !k.primary && k.listStatus !== '隐藏')
      .map((k) => ({
        label: k.fieldName,
        prop: k.colName,
        ext: k,
        ...(k.relationDictType
          ? {
              formatter: (row) => {
                return selectDictLabels(
                  dicts.value[
                    k.relationDictType === '系统字典'
                      ? k.sysDictType
                      : k.relationDictType === '常量字典'
                        ? `${k.colName}_TYPE`
                        : Symbol()
                  ] || [],
                  row[k.colName],
                );
              },
            }
          : {}),
      }));
  }

  function getFormConditionList() {
    const singleValueQuery = ['eq', 'gt', 'gte', 'lt', 'lte', 'like'];
    const listValueQuery = ['in', 'findInSet'];
    const rangeValueQuery = ['range'];

    const formConditionList = Object.keys(queryParams.value)
      .filter((k) => {
        const v = queryParams.value[k];
        if (!v) {
          return false;
        }
        if (Array.isArray(v) && v.length === 0) {
          return false;
        }
        return true;
      })
      .map((k) => {
        const oprType = queryField.value.filter((m) => m.field === k)?.[0]?.ext?.queryCondition;
        const v = queryParams.value[k];

        return {
          field: k,
          oprType: oprType,
          singleValue: singleValueQuery.includes(oprType) && !Array.isArray(v) ? v : '',
          listValue: listValueQuery.includes(oprType) || Array.isArray(v) ? v : [],
          ...(rangeValueQuery.includes(oprType) && Array.isArray(v) && v.length === 2
            ? {
                rangeValue: {
                  from: v[0],
                  to: v[1],
                },
              }
            : {}),
        };
      });

    return formConditionList;
  }

  async function checkId() {
    const { id, tableCode } = route.query;
    if (!id || !tableCode) {
      modal.msgError('id、tableCode不能为空');
      return;
    }

    const res = await getTable(id);
    permissionPrefix.value = `web:bu:form:curd:${id}`;
    const formCols = res.data.formCols.sort((a, b) => a.sortValue - b.sortValue);
    primaryKey.value = formCols.find((k) => k.primary)?.colName ?? 'ID';

    // 获取字典项
    await scanDict(formCols);
    // 拼接搜索项和搜索参数
    genQueryField(formCols);
    // 拼接表单项和表单参数
    genFormField(formCols);
    // 拼接列表项
    genTableField(formCols);

    getList.value = function () {
      loading.value = true;
      const formConditionList = getFormConditionList();
      listItem(tableCode, pageParams.value, { formConditionList })
        .then((res) => {
          list.value = res?.data?.records ?? [];
          total.value = res?.data?.total ?? 0;
        })
        .finally(() => {
          loading.value = false;
        });
    };

    reset.value = function () {
      form.value = { ...formParams.value };
    };

    cancel.value = function () {
      open.value = false;
      reset.value();
    };

    handleQuery.value = function () {
      pageParams.value.pageNum = 1;
      getList.value();
    };

    handleAdd.value = function () {
      reset.value();
      title.value = '新增';
      open.value = true;
    };

    handleUpdate.value = function (row) {
      reset.value();
      const id = row?.[primaryKey.value] ?? ids.value?.[0];
      getItem(tableCode, { [primaryKey.value]: id }).then((res) => {
        form.value = res.data;
        title.value = '修改';
        open.value = true;
      });
    };

    submitForm.value = function () {
      if (form.value?.[primaryKey.value]) {
        updateItem(tableCode, form.value).then(() => {
          modal.msgSuccess('修改成功');
          open.value = false;
          getList.value();
        });
      } else {
        addItem(tableCode, form.value).then(() => {
          modal.msgSuccess('新增成功');
          open.value = false;
          getList.value();
        });
      }
    };

    handleDelete.value = function (row) {
      const idList = row?.[primaryKey.value] ? [row[primaryKey.value]] : ids.value;
      modal
        .confirm(`是否确认删除此数据项？`)
        .then(() => {
          return delItem(tableCode, idList);
        })
        .then(() => {
          getList.value();
          modal.msgSuccess('删除成功');
        });
    };

    handleDownloadTpl.value = function () {
      downloadTpl(tableCode, `${res.data.tableRemark}导入模板.xlsx`);
    };

    handleExport.value = function () {
      const formConditionList = getFormConditionList();
      exportData(
        tableCode,
        pageParams.value,
        { formConditionList },
        `${res.data.tableRemark}导出数据.xlsx`,
      );
    };

    handleImportData.value = function (...args) {
      return importData(tableCode, ...args);
    };

    isReady.value = true;
    getList.value();
  }

  checkId();
</script>
